<?php

DEFINE( 'DOCTYPE_HTML_401_STRICT', '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">' );
DEFINE( 'DOCTYPE_HTML_401_TRANSITIONAL', '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">' );
DEFINE( 'DOCTYPE_HTML_401_FRAMESET', '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">' );
DEFINE( 'DOCTYPE_XHTML_10_STRICT', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' );
DEFINE( 'DOCTYPE_XHTML_10_TRANSITIONAL', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' );
DEFINE( 'DOCTYPE_XHTML_10_FRAMESET', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">' );
DEFINE( 'DOCTYPE_XHTML_11', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">' );

DEFINE( 'TAG_COMMENT', '!--' );
DEFINE( 'TAG_DOCTYPE', '!DOCTYPE' );
DEFINE( 'TAG_A', 'a' );
DEFINE( 'TAG_ABBR', 'abbr' );
DEFINE( 'TAG_ACRONYM', 'acronym' );
DEFINE( 'TAG_ADDRESS', 'address' );
DEFINE( 'TAG_AREA', 'area' );
DEFINE( 'TAG_BOLD', 'b' );
DEFINE( 'TAG_BASE', 'base' );
DEFINE( 'TAG_BDO', 'bdo' );
DEFINE( 'TAG_BIG', 'big' );
DEFINE( 'TAG_BLOCKQUOTE', 'blockquote' );
DEFINE( 'TAG_BODY', 'body' );
DEFINE( 'TAG_BR', 'br' );
DEFINE( 'TAG_BUTTON', 'button' );
DEFINE( 'TAG_CAPTION', 'caption' );
DEFINE( 'TAG_CITE', 'cite' );
DEFINE( 'TAG_CODE', 'code' );
DEFINE( 'TAG_COL', 'col' );
DEFINE( 'TAG_COLGROUP', 'colgroup' );
DEFINE( 'TAG_DD', 'dd' );
DEFINE( 'TAG_DEL', 'del' );
DEFINE( 'TAG_DIV', 'div' );
DEFINE( 'TAG_DFN', 'dfn' );
DEFINE( 'TAG_DL', 'dl' );
DEFINE( 'TAG_DT', 'dt' );
DEFINE( 'TAG_EM', 'em' );
DEFINE( 'TAG_FIELDSET', 'fieldset' );
DEFINE( 'TAG_FORM', 'form' );
DEFINE( 'TAG_FRAME', 'frame' );
DEFINE( 'TAG_FRAMESET', 'frameset' );
DEFINE( 'TAG_H1', 'h1' );
DEFINE( 'TAG_H2', 'h2' );
DEFINE( 'TAG_H3', 'h3' );
DEFINE( 'TAG_H4', 'h4' );
DEFINE( 'TAG_H5', 'h5' );
DEFINE( 'TAG_H6', 'h6' );
DEFINE( 'TAG_HEAD', 'head' );
DEFINE( 'TAG_HR', 'hr' );
DEFINE( 'TAG_HTML', 'html' );
DEFINE( 'TAG_I', 'i' );
DEFINE( 'TAG_IFRAME', 'iframe' );
DEFINE( 'TAG_IMG', 'img' );
DEFINE( 'TAG_INPUT', 'input' );
DEFINE( 'TAG_INS', 'ins' );
DEFINE( 'TAG_KBD', 'kbd' );
DEFINE( 'TAG_LABEL', 'label' );
DEFINE( 'TAG_LEGEND', 'legend' );
DEFINE( 'TAG_LI', 'li' );
DEFINE( 'TAG_LINK', 'link' );
DEFINE( 'TAG_MAP', 'map' );
DEFINE( 'TAG_META', 'meta' );
DEFINE( 'TAG_NOFRAMES', 'noframes' );
DEFINE( 'TAG_NOSCRIPT', 'noscript' );
DEFINE( 'TAG_OBJECT', 'object' );
DEFINE( 'TAG_OL', 'ol' );
DEFINE( 'TAG_OPTGROUP', 'optgroup' );
DEFINE( 'TAG_OPTION', 'option' );
DEFINE( 'TAG_P', 'p' );
DEFINE( 'TAG_PARAM', 'param' );
DEFINE( 'TAG_PRE', 'pre' );
DEFINE( 'TAG_Q', 'q' );
DEFINE( 'TAG_SAMP', 'samp' );
DEFINE( 'TAG_SCRIPT', 'script' );
DEFINE( 'TAG_SELECT', 'select' );
DEFINE( 'TAG_SMALL', 'small' );
DEFINE( 'TAG_SPAN', 'span' );
DEFINE( 'TAG_STRONG', 'strong' );
DEFINE( 'TAG_STYLE', 'style' );
DEFINE( 'TAG_SUB', 'Sub' );
DEFINE( 'TAG_SUP', 'sup' );
DEFINE( 'TAG_TABLE', 'table' );
DEFINE( 'TAG_TBODY', 'tbody' );
DEFINE( 'TAG_TD', 'td' );
DEFINE( 'TAG_TEXTAREA', 'textarea' );
DEFINE( 'TAG_TFOOT', 'tfoot' );
DEFINE( 'TAG_TH', 'th' );
DEFINE( 'TAG_THEAD', 'thead' );
DEFINE( 'TAG_TITLE', 'title' );
DEFINE( 'TAG_TR', 'tr' );
DEFINE( 'TAG_TT', 'tt' );
DEFINE( 'TAG_UL', 'ul' );
DEFINE( 'TAG_VAR', 'var' );

DEFINE( 'META_HTTPEQUIV', 'http-equiv' );
DEFINE( 'META_NAME', 'name' );
DEFINE( 'META_SCHEME', 'scheme' );

interface CoreAttributes {
	// not valid in: ( 'base', 'head', 'html', 'meta', 'param', 'script', 'style', 'title' )
	public function getClassName();
	public function setClassName( $value );

	public function getID();
	public function setID( $value );

	public function getStyle();
	public function setStyle( $value );

	public function getTitle();
	public function setTitle( $value );
}

interface LanguageAttributes {
	//Not valid in: ( 'base', 'br', 'frame', 'frameset', 'hr', 'iframe', 'param', 'script' )
	public function getDir();
	public function setDir( $value );
	
	public function getLang();
	public function setLang( $value );
}

interface KeyboardAttributes {
	public function getAccessKey();
	public function setAccessKey( $value );

	public function getTabIndex();
	public function setTabIndex( $value );
}

class HTMLElement { // implements KeyboardAttributes {

	private static $xhtml = false;

	protected $element;
	protected $attributes;
	protected $children;
	protected $selfclosing;

	public function __construct( $element, $selfclosing ) {
		$this->element = $element;
		$this->selfclosing = $selfclosing;
		$this->attributes = array();
		$this->children = array();
	}

	public static function getXHTML() { return HTMLElement::$xhtml; }
	public static function setXHTML( $value ) { HTMLElement::$xhtml = $value; }

	public function getElement() { return $this->element; }
	public function setElement( $value ) { $this->element = strtolower( $value ); }

	public function getChildren() { return $this->children; }
	public function setChildren( array $children ) { $this->children = $children; }
	
	public function appendLiteral( $value ) {
		$this->children[] = $value;	
	}
	
	public function appendChild( $value ) { $this->children[] = $value; }
	
	public function appendChildren() {
		foreach( func_get_args() as $child ) {
			$this->children[] = $child;
		}
	}
	
	public function render() {
		$output = '<' . $this->element;
		
		foreach( $this->attributes as $name => $value ) {
			if( empty( $value ) ) continue;
			$output .= ' ' . $name . '="' . htmlspecialchars( $value ) . '"';
		}
		
		if( $this->selfclosing ) {
			$output .= ( HTMLElement::$xhtml ? ' />' : '>' );
		} else {
			$output .= '>';
			
			foreach( $this->children as $child ) {
				if( is_string( $child ) ) {
					$output .= htmlspecialchars( $child );
				} else if( is_numeric( $child ) ) {
					$output .= (string)$child;
				} else if( is_object( $child ) ) {
					$output .= $child->render();
				}
			}
			
			$output .= '</' . $this->element . '>';
		}
		
		return $output;
	}

}

class HTML extends HTMLElement {
	
	public function __construct() {
		parent::__construct( TAG_HTML, false );
	}
	
}

class Head extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_HEAD, false );
	}

}

class Title extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_TITLE, false );
	}

}

class Body extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_BODY, false );
	}

}

class Base extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_BASE, true );
	}

}

class Anchor extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_A, false );
	}

	public function getHref() { return $this->attributes[ 'href' ]; }
	public function setHref( $value ) { $this->attributes[ 'href' ] = $value; }

}

class Image extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_IMG, true );
	}

	public function getAlt() { return $this->attributes[ 'alt' ]; }
	public function setAlt( $value ) { $this->attributes[ 'alt' ] = $value; }

	public function getSrc() { return $this->attributes[ 'src' ]; }
	public function setSrc( $value ) { $this->attributes[ 'src' ] = $value; }

}

class Br extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_BR, true );
	}

}

class Paragraph extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_P, false );
//		$this->appendChildren( func_get_args() );
	}

}

class Div extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_DIV, false );
	}

}

class Header extends HTMLElement {

	public function __construct( $level ) {
		if( is_numeric( $level ) && ( $level >= 1 && $level <= 6 ) ) {
			$tag = 'h' . $level;
		} else {
			$tag = 'h1';
		}
		
		parent::__construct( $tag, false );
	}
}

class UnorderedList extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_UL, false );
	}

	public function appendLiteral( $value ) {}	
	public function appendChild( $value ) {}	
	public function appendChildren() {}

}

class OrderedList extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_OL, false );
	}

	public function appendLiteral( $value ) {}	
	public function appendChild( $value ) {}	
	public function appendChildren() {}

}

class ListItem extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_LI, false );
	}

}

class Input extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_INPUT, true );
	}


}

class TextArea extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_TEXTAREA, false );
	}
}

class Meta extends HTMLElement {

	public function __construct( $key, $value, $metatype = META_NAME ) {
		parent::__construct( TAG_META, true );
	}
	
	public function getHttpEquiv() { return $this->attributes[ META_HTTPEQUIV ]; }
	public function setHttpEquiv( $value ) { $this->attributes[ META_HTTPEQUIV ] = $value; }
	
	public function getName() { return $this->attributes[ META_NAME ]; }
	public function setName( $value ) { $this->attributes[ META_NAME ] = $value; }
	
	public function render() {
	
	}

}

class Script extends HTMLElement {

	public function __construct() {
		parent::__construct( TAG_SCRIPT, false );
	}
	
}


// Keyboard Attributes
// accesskey 	character					Sets a keyboard shortcut to access an element
// tabindex 	number						Sets the tab order of an element
